namespace ds
{

    /**
     * 并查集项
     */
    export class DisjointSetItem<T>
    {
        /**
         * 值
         */
        value: T;
        /**
         * 计算键值函数
         */
        keyCallback: (value: T) => string;

        /**
         * 父项
         */
        parent: DisjointSetItem<T>;
        /**
         * 子项
         */
        // children: { [key: string]: DisjointSetItem<T> };
        children: any;

        /**
         * 构建 并查集 项
         * 
         * @param value 值
         * @param keyCallback 计算键值函数
         */
        constructor(value: T, keyCallback?: (value: T) => string)
        {
            this.value = value;
            this.keyCallback = keyCallback;
            this.parent = null;
            this.children = {};
        }

        /**
         * 获取键值
         */
        getKey()
        {
            if (this.keyCallback)
            {
                return this.keyCallback(this.value);
            }
            return <string><any>this.value;
        }

        /**
         * 获取根项
         */
        getRoot(): DisjointSetItem<T>
        {
            return this.isRoot() ? this : this.parent.getRoot();
        }

        /**
         * 是否为根项
         */
        isRoot()
        {
            return this.parent === null;
        }

        /**
         * 获取所有子孙项数量
         */
        getRank()
        {
            if (this.getChildren().length === 0)
            {
                return 0;
            }

            let rank = 0;

            this.getChildren().forEach((child) =>
            {
                rank += 1;
                rank += child.getRank();
            });

            return rank;
        }

        /**
         * 获取子项列表
         */
        getChildren()
        {
            var values = Object.keys(this.children).map(key => this.children[key]);
            return values;
        }

        /**
         * 设置父项
         * @param parentItem 父项
         */
        setParent(parentItem: DisjointSetItem<T>)
        {
            this.parent = parentItem;
            this.parent.children[this.getKey()] = this;
            return this;
        }

        /**
         * 添加子项
         * @param childItem 子项
         */
        addChild(childItem: DisjointSetItem<T>)
        {
            this.children[childItem.getKey()] = childItem;
            childItem.parent = this;
            return this;
        }
    }
}